package rad.framework.mda.generator.engine;

import java.lang.reflect.InvocationTargetException;

import rad.framework.mda.generator.Console;
import rad.framework.mda.generator.GeneratorPlugin;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.uml2.uml.Activity;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Region;
import org.eclipse.uml2.uml.StateMachine;

/**
 * @author boudyacho
 * 
 */
public class Engine {

	private Element element;

	public Engine(Element object) {
		this.element = object;
	}

	protected Element getElement() {
		return element;
	}

	public void generateAll() {
		Console.getStream().println("*** Start Generate All ************");
		generate(true, null, null, null, null);
		Console.getStream().println("*** End Generate ******************");
	}
	
	public void generateForExtension(String extension) {
		Console.getStream().println("*** Start Generate Mergable *******");
		generate(false, extension, null, null, null);
		Console.getStream().println("*** End Generate ******************");
	}

	public void generateForPlugin(String plugin) {
		Console.getStream().println("*** Start Generate for Plugin *****");
		generate(false, null, plugin, null, null);
		Console.getStream().println("*** End Generate ******************");
	}

	public void generateForSuffix(String suffix) {
		Console.getStream().println("*** Start Generate for Suffix *****");
		generate(false, null, null, suffix, null);
		Console.getStream().println("*** End Generate ******************");
	}

	public void generate(Template template) {
		Console.getStream().println("*** Start Generate for Template ***");
		generate(false, null, null, null, template);
		Console.getStream().println("*** End Generate ******************");
	}

	public void generate(final boolean all, final String extension,
			final String plugin, final String suffix, final Template template) {

//		javaFiles.clear();
		
		WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
			public void execute(IProgressMonitor monitor) throws CoreException,
					InvocationTargetException, InterruptedException {

				ElementProcessor processor = getElementProcessor(getElement());
				processor.process(getElement(), all, extension, plugin, suffix,
						template, monitor);
			}
		};

		run(op);
		
//		op = new WorkspaceModifyOperation() {
//			public void execute(IProgressMonitor monitor) throws CoreException,
//					InvocationTargetException, InterruptedException {
//
//				organizeImports();
//			}
//		};
//
//		run(op);
	}

	protected void run(WorkspaceModifyOperation op) {
		Shell shell = GeneratorPlugin.getActiveWorkbenchShell();
		ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell);
		try {
			dialog.run(false, true, op);
		} catch (Exception e) {
			MessageDialog.openError(Display.getDefault().getActiveShell(),
					"Generation Exception", e.toString());
			throw new RuntimeException(e);
		}
	}

	static ElementProcessor getElementProcessor(Element element) {
		if (element instanceof Package) {
			return new PackageProcessor();
		}
		if (element instanceof StateMachine) {
			return new StateMachineProcessor();
		}
		if (element instanceof Region) {
			return new RegionProcessor();
		}
		if (element instanceof Activity) {
			return new ActivityProcessor();
		}
		if (element instanceof org.eclipse.uml2.uml.UseCase) {
			return new UseCaseProcessor();
		}
		if (element instanceof org.eclipse.uml2.uml.Class) {
			return new ClassProcessor();
		}
		return new NamedElementProcessor();
	}

	@SuppressWarnings("unchecked")
	static TemplateProcessor getTemplateProcessor(Template template) {
		String processorClass = template.processorClass;
		if (processorClass == null) {
			return new BasicTemplateProcessor();
		} else {
			try {
				java.lang.Class processor = java.lang.Class
						.forName(processorClass);
				return (TemplateProcessor) processor.newInstance();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}
}
